home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1993 / MacHack 1993.toast / MacHack™ 1987-1992 / MacHack™ '90 / Other Stuff / Demos ƒ / Word Solution Engine DEMO / Raw Text Files / Large Raw Text next >
Encoding:
Text File  |  1990-06-06  |  82.8 KB  |  1,846 lines  |  [TEXT/WSDP]

  1. This is a large file sample merely to show the superiority to TextEdit. Word Solution can handle up to 16 megabytes of text.
  2.  
  3. -----------------------------------------------------------------
  4.  
  5. Word Solution Engine™    Beta v0.902  31 May 1990
  6.  
  7. General Description
  8.  
  9. Word Solution Engine (WS) is an object code module which can be included in a Macintosh application to provide a developer with text editing far superior to the existing Macintosh tools.
  10.  
  11. Using the object code along with this Programmer's Guide,  WS literally becomes an extension to the Mac Toolbox.
  12.  
  13. Getting Started
  14.  
  15. Word Solution Engine is an object-code module  to be included with your application.
  16.  
  17. Regardless of what language you developing in, there are two approaches you may take for hooking into WS.
  18.  
  19. On the "WS Engine-Object" disk you received from DataPak there is a Folder called LINKABLE OBJECT and another called RES OBJECT.
  20.  
  21. The linkable object  Folder contains the necessary object-code files you can directly link into your application program; the res object  Folder contains the same WS object-code except it is in the form of an independent resource that loads externally to your program.
  22.  
  23. The difference between the two types of object files are simply the way  they get included into your program -- both are exactly the same in all other respects.
  24.  
  25. The linkable  object, at this time, is limited to MPW Pascal, MPW C, MPW Assembler, Think C, and Think Pascal.
  26.  
  27. The res object  is essentially not limited to any Mac programming environment since it loads and runs independently of your compiled code.
  28.  
  29. The linkable version is mainly used for stand-alone applications while the res version is used for Desk Accessories, Hypercard externals, etc. where the code cannot depend upon the Segment Loader or register A5.
  30.  
  31.  
  32. STEPS TO INCLUDE THE LINKABLE OBJECT
  33.  
  34.  
  35. 1. You will only need the files in the linkable object  folder.
  36.  
  37. 2. For PASCAL, include the "WSIntf.p" as a unit to obtain all the predefined constants, procedures and functions;  for "C", include "WSInft.h" as a header file to reference all the structures and functions outlined in this manual.
  38.  
  39. 3. Write your program by following the routines given in Section II and III, "Using Word Solution" and "WS Routines".
  40.  
  41. 4. At link time, include the WS object code file.  For MPW, use Core.Linked.a.o;  for Think C, use Core.Linked.a.π and use the Core.Linked.v file for vocabulary (case definitions).
  42. STEPS TO INCLUDE THE RES OBJECT
  43.  
  44. 1. You will only need the files in the res object  folder.
  45.  
  46. 2. For PASCAL, include the "WSIntf.p" as a unit to obtain all the predefined constants, procedures and functions;  for "C", include "WSInft.h" as a header file to reference all the structures and functions outlined in this manual.
  47.  
  48. 3. Write your program by following the routines given in Section II and III, "Using Word Solution" and "WS Routines".
  49.  
  50. 4. At link time, include the small object file that provides "glue" between your program and the WS "code" resource.  For MPW, use "wp.ResGlue.a.o";  for Think C, use "wp.ResGlue.a.π" and use the "wp.ResGlue.a.v" file for vocabulary (case definitions).
  51.  
  52. 5. If you have not done so already, install the resource 'WSXT' into your application resource file (or the System file, whichever is appropriate to your situation -- the idea is the resource must be loadable at run-time).  The 'WSXT' resource can be found in the "WS.Resource" file also included in the res object  folder.
  53.  
  54.  
  55.  
  56. Word Solution Basics
  57.  
  58.  
  59. All the routines given in this manual work exactly the same as those found in Inside Macintosh.
  60.  
  61. If you have included the object code and interface files correctly (explained in "Getting Started," above), every WS routine is available to your application.
  62.  
  63. Depending upon your development intentions, parts of this manual may be skipped. To help in this manner, here is a brief outline of its sections:
  64.  
  65.  
  66. I. Record Structures.  This section explains the various record structures used by WS. If you're only going to do very basic editing, almost all of this section can be skipped.
  67.  
  68. II. Using Word Solution. This section outlines the general steps for creating an application with WS. For Mac "veterans" much of this section can be skipped.
  69.  
  70. III. WS Routines. This section documents each WS routine, broken down by various topics. There is no way, of course, you can skip this section entirely since these are the routines you will be using in your program.
  71.  
  72. IV. Advanced Techniques. This section covers the subject of customizing text display and using WS low-level hooks.  If you're not planning these advance techniques, skip this section.
  73.  
  74.  
  75. I. Record Structures
  76.  
  77.  
  78. This section describes the data structures used by WS.  It is not necesssary to know everything about these structures to effectively use Word Solution Engine.  This information is provided mainly to offer programmer's wide versatility and comprehension of the internals.
  79.  
  80.  
  81. Almost every Procedure and Function involve the WSHandle  whose structure is as follows:
  82.  
  83.     WSHandle = ^WSPtr;
  84.     WSPtr = ^WSRec;
  85.     WSRec = Record
  86.         tHandle:TextStuff;    { Handle to text structures }
  87.         tLength:LongInt;    { Total length of text }
  88.         tRect:Rect;    { Display rectangle }
  89.         tBounds:LongRect;    { Bounds "rectangle" }
  90.         thBase:LongInt;    { Original h-scroll position }
  91.         tvBase:LongInt;    { Original v-scroll position }
  92.         tBegin:tSelectPos;    { Begin selection }
  93.         tEnd:tSelectPos;    { End Selection }
  94.         tCalc:tSelectPos;    { Next place to recalc }
  95.         tCalcEnd:tSelectPos;    { Place to end recalc }
  96.         tTop:tSelectPos;    { Top visible line in tRect }
  97.         tFormat:FormatHandle;    { Format Run }
  98.         tFmt:FormatRec;    { Current Format (of caret position) }
  99.         tJust:Integer;    { Justification of text }
  100.         tFlags:LongInt;    { Misc. attributes }
  101.         tArrow:Integer;    { Used for arrow keys }
  102.         tRefCon:LongInt;    { For application use }
  103.         tProcs:WSHooksPtr;    { Hooks for a variety of stuff }
  104. { Remainder for use by Levels 1 and 2 }
  105.     END;
  106.  
  107. Here is a brief description for each field of the WSRec:
  108.  
  109. tHandle. Contains a specially defined handle for text structures to be edited or displayed. (The variable, TextStuff, is defined later on under "Text Buffering").
  110.  
  111. tLength. The total length of text. NOTE: This is never zero -- there are always two null (0) characters at the end of the text.
  112.  
  113. tRect.  The area rectangle, in local coordinates, where the text structure may display. It differs from tBounds (below) in that tRect merely "clips" the visual display while tBounds defines the relative text display ("scrolled" state) and the maximum width for word wrapping (see the illustration for the function, "WSNew").
  114.  
  115. tBounds.  The area the text display gets pinned to, in local co-ordinates.  In essence, the position of tBounds defines the visual "scrolled" position (see WSNew, below).
  116.  
  117. However, since WScan handle extremely large amounts of text, it is conceivable that tBounds could scroll past the boundaries of 32,768;  thus, tBounds is defined as an expanded rectangle structure as follows:
  118.  
  119. LongRect = RECORD
  120. Top:LongInt;    { "Top" side }
  121. Left:LongInt;    { "Left" side }
  122. Bottom:LongInt;    { "Bottom" side }
  123. Right:LongInt;    { "Right" side }
  124. END;
  125.  
  126.  
  127. thBase, tvBase.  The original left and top edges, respectively, of tBounds. This is used by WS to maintain knowledge of where the contents are "scrolled."
  128.  
  129. tBegin, tEnd. The beginning and ending selection points, respectively. A tSelectPos  is predefined as follows:
  130.  
  131.  
  132. TYPE tSelectPos = RECORD
  133.     Pos:LongInt;    { Offset into text }
  134.     Buffer:LongInt;    { Offset into text buffer array }
  135.     Line:LongInt;    { Offset into Line Array }
  136.     Caret:Integer;    { "Caret" or left-edge, in pixels }
  137.     END;
  138.  
  139.  
  140.      The Pos  value gives the absolute offset into the text;  Buffer  is an offset into an array of text buffers which contains Pos  offset (see "Text Buffering");  Line  is the absolute offset into the concatenated line arrays for each text buffer, while Caret  is the pixel offset of the insertion point (of left edge of highlighted text).
  141.  
  142. For the most part, your application won't need to use any of these fields -- the information you might need is usually obtainable through various procedures and functions.
  143.  
  144.  
  145. tCalc, tCalcEnd. These are tSelectPos records (defined above) which get set by various WS routines whenever text needs to be recalculated (such as changes in Font, word wrapping, etc.). Unless you are doing something unusually fancy, you generally won't need to see or change this information.
  146.  
  147.  
  148. tTop. This is the first visible line within the visual rectangle. It is defined as a tSelectPos record, explained above. It is maintained internally by WS and doesn't need to be updated by your application.
  149.  
  150.  
  151. tFormat. This is the format run  for the entire text structure (information about Font, Style, etc.) whose predefined structure is as follows:
  152.  
  153.  
  154. FormatRec = RECORD
  155. Pos:LongInt;    { Offset to text }
  156. UserProcs:UserStylesPtr;     { Pointer to User Style routines }
  157. fReal:Integer;    { Font is "real" if non-zero }
  158. fName:String[31];    { Font Name }
  159. fStyle:Integer;    { Text style }
  160. fPoint:Fixed;    { Point size (fractional) }
  161. fgColor:RGBColor;    { Foreground color }
  162. Txr:Integer;    { Transfer mode (Color systems only) }
  163. cExtra:Fixed;    { CharExtra value (char spacing) }
  164. Leading:Integer;    { +- offset for baseline }
  165. UserSpace:LongInt;    { Space provided for UserStyles }
  166. END;
  167.  
  168. FormatPtr = ^FormatRec;
  169.  
  170. FormatHandle = ^FormatPtr;
  171. FormatAPtr = ^FormatArray;
  172. FormatArray = ARRAY[0..0] OF FormatRec;
  173.  
  174.  
  175. Field Pos  contains the absolute offset into text where this format record begins.
  176.  
  177. UserProcs  is a pointer to low-level routines which an application can hook into to create custom styles and specialized displays.  UserProcs contains either NIL (which means WS will handle text stylations itself) or a pointer to a predefined structure, UserStyles. SEE "LOW-LEVEL HOOK ROUTINES" AND "USER STYLES" IN THE LAST SECTION OF THIS MANUAL FOR MORE INFORMATION.
  178.  
  179. Field fReal  is non-zero if the combination font and point size is a "real" font (not scaled).
  180.  
  181. Field fName is the name of the font used for this format run. WS uses font names (as opposed to integers) to be compatible with all future systems.
  182.  
  183. Field fStyle  is the textface value for the text, represented by the following bits:
  184.  
  185. Bits 0-7    Standard Quickdraw style bits
  186. Bit 8-15    ** reserved for future enhancement **
  187.  
  188. Field fPoint  is a fixed point variable defining the point size.  Note that fractional  point sizes can be recorded and retrieved for each style run;  however, the current version of WS only looks at the high-order word of fStyle (whole integer) but a fixed  variable has been given for future enhancement.
  189.  
  190. Field fgColor   is an RGBColor defining the foreground color of the text. This will only have effect in a Color Quickdraw environment.
  191.  
  192. Field Txr  is taken as the text transfer mode.  However, the current version of WS does not use this field and is reserved for future enhancement.
  193.  
  194. Field cExtra  is a fixed point variable used to extend or condense characters ("CharExtra") and allow for variable character spacing (for kerning features, etc.). However,  the current version of WS does not use this field and is reserved for future enhancement.
  195.  
  196. Leading  is reserved for future "add-on" style enhancements.
  197.  
  198. UserSpace  is provided for the application using User Styles.  This space will never be changed by WS and can be used for any purpose by the application.
  199.  
  200.  
  201. tFmt.  This field contains the current format record of the insertion point (or the overall format for the selection range).  The record structure is a FormatRec defined above.
  202.  
  203. tJust.  This defines the overall justification of the text structure as follows:
  204.  
  205.  
  206. 0 -- Left Justify
  207. 1 -- Center Justify
  208. 2 -- Right Justify
  209. 3 -- Full Justify
  210.  
  211. For WS, there is only one field for justification (affecting all  text).
  212.  
  213. tFlags.  This contains 32 bits of information for specific attributes of the text.
  214.  
  215. At this time, tFlags contain the following possible attributes:
  216.  
  217.  
  218. CONST    NoWrap =    1;    { If set, no text wrapping }
  219.     CaretOn =    2;    { Caret is currently displaying }
  220.     NeedsCalc = 4;    { Text needs recalculating }
  221.     Deactive =    8;    { Inactive state }
  222.     ViewOnly =    16;    { No editing -- view-only }
  223.  
  224.  
  225. { Other bits reserved for future enhancement }
  226.  
  227.  
  228. tArrow. This is used internally for up and down arrow key control.
  229.  
  230. tRefCon. This long integer space can be used for anything by the application.
  231.  
  232. tProcs.  This contains a pointer to an array of low-level WS routines that the application may hook into for specialized features. The format and description for each low-level routine is described in detail under "Low-Level Hook Routines" in the last section of this manual.
  233.  
  234.  
  235.  
  236. Text Buffering
  237.  
  238.  
  239. In order to handle very large blocks of text at optimum speed, WS breaks the text stream into individual text buffers. This also provides easy enhancement for disk buffering, etc. An individual text buffer is predefined as follows:
  240.  
  241. TextBlock = RECORD
  242. TBBegin:LongInt;    { Absolute text beginning }
  243. TBEnd:LongInt;    { Absolute text end }
  244. TBLines:LineHandle;    { Line array }
  245. TBLineBeg:LongInt;    { Absolute line beginning }
  246. TBLineEnd:LongInt;    { Absolute line ending }
  247. TBPixBeg:LongInt;    { Pixel height beginning }
  248. TBPixEnd:LongInt;    { Pixel height ending }
  249. TBFlags:LongInt;    { Misc. attributes }
  250. TBHandle:CharsHandle;    { Actual text }
  251. TBCTL:Handle;    { Control Char Run }
  252. TBLev1:LongInt;    { Reserved for future }
  253. TBLev2:LongInt;    { Reserved for future }
  254. END;
  255.  
  256.  
  257. Most of the fields in the text block record will only be used internally by WS. However, here is a brief description for some of the important fields:
  258.  
  259. TBBegin, TBEnd. The absolute beginning and ending of text, respectively, as if all text buffers were contiguous.
  260.  
  261. TBLines.  Contains the line array of the text in this block.  The line array is described in detail later on.
  262.  
  263. TBLineBeg, TBLineEnd.  The beginning and ending offsets of the line array relative to the entire WS structure.
  264.  
  265. TBPixBeg, TBPixEnd. The pixel position of the beginning and ending lines relative to the entire WS structure.
  266.  
  267. TBHandle.  The text itself for this block.  If this is the last (ending) text block, the text contains two NUL (0) characters as a terminator.
  268.  
  269. All other fields are used internally by WS and should never be altered by the application.
  270.  
  271. Text blocks are maintained by WS as an array of handles:
  272.  
  273.  
  274. TextStuff = ^TextArrayPtr;
  275. TextArrayPtr = ^TextArray;
  276. TextArray = ARRAY[0..0] OF TextBlock;
  277.  
  278.  
  279. The Line Array
  280.  
  281.  
  282. WS maintains an array of records defining line and word breaks for each text buffer.
  283.  
  284. A line array entry is predefined as follows:
  285.  
  286. LineRec = RECORD
  287. Pos:LongInt;    { Offset into text where line begins }
  288. Length:Integer;    { Length of line }
  289. Top:LongInt;    { Relative top of line }
  290. Height:Integer;    { The line's total height, in pixels }
  291. Left:Integer;    { Amount to offset for line drawing }
  292. Base:Integer;    { Vertical baseline to draw text }
  293. Flags:Integer;    { Reserved for internal use }
  294. rNum:Integer;    { Reserved for internal use }
  295. Width:Integer;    { The line's total width, in pixels }
  296. DLength:Integer;    { Displayable length }
  297. END;
  298.  
  299.  
  300. The Pos  field contains the relative position into the text.  This position is relative to all text, not the text buffer that "owns" this line.
  301.  
  302. Length  contains the total length of the line.
  303.  
  304. Top  is the relative vertical pixel position used for display and selection purposes.  It is always relative to the tBounds field of WS -- it is not an absolute screen position.  The line's horizontal position is always assumed to be zero (relative to tBounds left position).
  305.  
  306. Height  is the line's total height, in pixels.
  307.  
  308. Left  is an optional distance to offset the line for drawing and mouse-clicks.  Note, however, that this is always zero by default unless the application (or future enhancement) alters it directly.
  309.  
  310. Base  is the vertical distance from the line's bottom edge to commence drawing (baseline).
  311.  
  312. Flags  and rNum  are used internally by WS and must never be altered.
  313.  
  314. Width  contains the total width of the line, in pixels.
  315.  
  316. DLength  is the lines displayable length.  This might be different than the Length field, for instance, on a line that ends with a RETURN character.
  317. Line arrays are maintained and grow dynamically using the following predefined structure:
  318.  
  319.     LineHandle = ^LineAPtr;
  320.     LineAPtr = ^LineArray;
  321.     LineArray = ARRAY[0..0] OF LineRec;
  322.  
  323.  
  324.  
  325. Global Parameters
  326.  
  327.  
  328. WS maintains a few global parameters (applied to all WSHandles) via the following predefined format:
  329.  
  330. WSGlobalsPtr = ^WSGlobals;
  331. WSGlobals = RECORD
  332. Version:LongInt;    { WS Software Version }
  333. MaxBufSize:LongInt;    { Maximum buffer size }
  334. Extension:ProcPtr;    { Called for extension modules }
  335. Script:LongInt;    { System + Application Script }
  336. QDBits:GrafPort;    { Offscreen bitmap port }
  337. QDPix:cGrafPort;    { Offscreen color pixmap port }
  338. PortBuf:Handle;    { Bits used for offscreen mapping }
  339. TabSpace:Integer;    { Default TAB spacing }
  340. Decimal:Integer;    { Decimal char }
  341. Return:Integer;    { RETURN char }
  342. LF:Integer;    { Line Feed char }
  343. Tab:Integer;    { TAB char }
  344. Backspace:Integer;    { Backspace char }
  345. Hyphen:Integer;    { Hyphenation char }
  346. END;
  347.  
  348.  
  349. Version. Contains the running version of WS.
  350.  
  351. MaxBufSize -- The maximum buffer size for a text block (see TextStuff format). The default value on start-up = 1536.
  352.  
  353. Extension -- A procedure pointer called by WS for special add-on extensions. The application shouldn't alter this field.
  354.  
  355. Script -- This field is non-zero if anything besides Roman script is being used. An example of non-Roman script would be Kanji (Japanese) Script.
  356.  
  357. QDBits, QDPix -- A GrafPort and cGrafPort to be used for offscreen drawing. Only Color Quickdraw environments will have QDPix.
  358.  
  359. PortBuf -- Contains bitmap memory for black and white bitmap drawing.
  360.  
  361. TabSpace -- The default tab stop value when there are no tab stops.  The default value is 24 pixels).
  362.  
  363. Decimal -- Reserved for future enhancement.
  364.  
  365. Return through Hyphen -- Contain the characters to be used for RETURN, LINEFEED, TAB, BACKSPACE, and HYPHEN (hyphenation), respectively.
  366.  
  367. Through various procedures and functions, the application can change the values for each of the fields above.
  368.  
  369. II. Using Word Solution Engine
  370.  
  371.  
  372. This section has been provided to give you a general understanding and overview for using Word Solution -- a more thorough description of each routine is given in the next section, WS Routines.
  373.  
  374. All of this section assumes you have a basic understanding of Inside Macintosh and Mac programming in general.
  375.  
  376.  
  377. Initialization
  378.  
  379. Before any WS routine can be accessed, you must call WSStartup -- this initializes all the global variables and internal memory structures of WS (as well as load the "code" resource if you are using the stand-alone resource object). If you're concerned about low-memory errors you need to pass a pointer to an error function at this time.
  380.  
  381. Then, to create an "empty" editing structure call WSNew and pass all the appropriate parameters to create the desired result.  The WSNew function returns a WSHandle which you will pass to almost every other function.
  382.  
  383. From this point you need to repeatedly call WSIdle to make the "caret" toggle for that particular WSHandle;  typically, WSIdle is called once during every GetNextEvent loop.
  384.  
  385.  
  386. NOTE:  Never at any time does WS "attach" itself to any particular window or GrafPort; all display and editing operations occur on the current GrafPort -- WS doesn't not "remember" what window was selected when you created a WSHandle.
  387.  
  388.  
  389. Once you are completely through using a WSHandle, call WSDispose.
  390.  
  391.  
  392. Response to Events
  393.  
  394.  
  395. The way you respond to Events is very similar to TextEdit:
  396.  
  397. For KeyEvents, call WSKey.
  398.  
  399. For MouseDown events, call WSClick. If you want to automatically scroll when the mouse drags through text, pass a pointer to such a procedure in the IdleProc parameter of WSClick.
  400.  
  401. For Activate events, determine whether it is a deactivate of activate event and call WSActivate or WSDeactivate, whichever applies.
  402.  
  403. For Update events, call WSDisplay.  Note that for this event, be sure to pass TRUE for displaying the selection range, otherwise the WSHandle might not visually update properly.
  404.  
  405. For scrolling in general, simply call WSScroll and WS updates the scrolled areas appropriately.
  406.  
  407. For a simple "test" program, the above is all you need to do to obtain the basics of text editing.
  408.  
  409. Changing Text Format
  410.  
  411. WS maintains multiple  stylations, that is, different characters can be any standard font, text face, and/or point size.
  412.  
  413. If a change is made to the text format while there is only an insertion point ("caret"), the change only occurs on the next  WSKey;  if a change is made while text is selected (highlighted), the change occurs immediately.
  414.  
  415.  
  416. NOTE: If text formatting changes immediately (becuase text is highlighted), it does not automatically re-display -- you need to call WSDisplay for the effect to be seen.
  417.  
  418.  
  419. To change the font, call WSSetFont.
  420.  
  421. To change the text face ("style"), call WSSetStyle.
  422.  
  423. To change the point size, call WSSetPoint.
  424.  
  425. To change the color (32-bit color), call WSSetColor.
  426.  
  427. To change text justification, call WSSetJust.  Note, however, that WS does not support unique justifications for individual paragraphs -- the justification affects all  text.
  428.  
  429. You can get information from a WSHandle as to which font, style, point size or color the selection range contains by calling WSGetFont, WSGetStyle, WSGetPoint and WSGetColor, respectively. You can get the justification by calling WSGetJust.
  430.  
  431.  
  432. Cut, Copy, Paste, and Undo
  433.  
  434.  
  435. WS provides a minimal set of routines to manipulate the "scrap."
  436.  
  437. If so desired, you can transform the external scrap to a WSHandle by calling WSScrapToHandle.
  438.  
  439. To delete selected text ("Cut" or "Clear"), call WSCut.
  440.  
  441. To copy a selected range, call WSCopy.
  442.  
  443. To "paste" text, call WSPaste to insert the results of a previous WSCopy.
  444.  
  445. Note that to perform a true "Cut" operation, you should first call WSCopy (causing the selected contents to transfer to the scrap) then WSCut to delete the text.
  446.  
  447. Although WS does not support an "Undo" as such, an Undo operation can be accomplished by using a combination of WSCut, WSCopy, and WSPaste.
  448.  
  449. You can perform a "format change" undo by using WSCopyFormat and WSApplyFormat.
  450.  
  451. You can draw a "clipboard" by merely displaying the results of WSCopy.
  452.  
  453. When your application quits, you can force WS's internal scrap into the Mac's external scrap by calling WSToScrap.
  454.  
  455. Inserting Raw Text
  456.  
  457.  
  458. WS provides several routines to transfer raw text to and from a WSHandle.
  459.  
  460. The easiest way is through WSSetText which replaces all text with the contents passed to it.
  461.  
  462. A more sophisticated way is to call WSText2New (which creates a new WSHandle from a block of text and a predefined format) then do a WSPaste using that handle.  This creates a raw text "insertion" and also allows you to control the particular text format of the insertion.
  463.  
  464. To obtain raw text from a WSHandle, call WSGetText to get all  text or WSGetSelText to obtain only the selected (highlighted) text.
  465.  
  466.  
  467. I/O & Printing Support
  468.  
  469.  
  470. WS provides to routines to aid the saving and retrieving of WSHandles (to a file, for instance). These are WSToHandle and HandleToWS, which converts a WSHandle to a single, contiguous data structure, or reverses the process, respectively.
  471.  
  472. For printing, use WSPrint (rather than WSDisplay) to obtain optimum results.  WSPrint also allows you to control where text is drawn on the page regardless of its currently scrolled position.
  473.  
  474.  
  475. Customizing Text & Advance Techniques
  476.  
  477.  
  478. Once you are thoroughly fimiliar with the basics of WS and wish to customize display and editing (such as graphic pictures or additional styles), refer to the last section of this manual, "Advance Techniques".
  479.  
  480.  
  481. Ending Off
  482.  
  483.  
  484. Before your application quits, call WSShutDown.  Note, however, that once WSShutDown is called you can no longer access any WS routine until you call WSStartup.
  485.  
  486. III. WS Routines
  487.  
  488.  
  489. Initialization & Maintenance
  490.  
  491.  
  492. PROCEDURE WSStartup (ResID:Integer; ErrorProc:ProcPtr);
  493.  
  494.  
  495. Initializes WS, allocating the code resource and allocates internal memory.
  496.  
  497. ResID is the resource number for a WSXT resource (Word Solution External) if you are using the stand-alone "code" resource method;  otherwise, ResID is ignored.  The default ResId = 128.
  498.  
  499. ErrorProc is an optional pointer to a function that is called if WS runs out of memory. It is taken in the form of:
  500.  
  501. FUNCTION MyErrorProc (cbNeeded:LongInt):Boolean;
  502.  
  503. The cbNeeded parameter contains the amount of memory that WS is short (this value is taken from the GrowZone procedure outlined in the Memory Manager).  If the function returns TRUE, then WS retries for memory allocation;  if it fails again, the error procedure is called.  This process is repeated until either memory is successfully allocated or the function returns FALSE.
  504.  
  505. If the ErrorProc returns FALSE, WS will gracefully back out of whatever it was doing (which includes disposing all memory that it had temporarily created during the current action) and return control to the application.  An example where this might occur is a massive WSPaste call that runs out of memory half way through the "paste" process -- once the application tells WS to give up via the error procedure, WS would dispose the half-way paste and return from the WSPaste function.
  506.  
  507. Note: If you provide an error procedure, WS calls SetGrowZone to intercept tight memory situations;  if you are calling SetGrowZone as well it will never get to the WS error procedure.
  508.  
  509. Besides out-of-memory, there is one other error that gets reported:
  510.  
  511. -1    Buffer too large with no RETURN of LF.
  512.  
  513. If cbNeeded returns -1, too much text exists in a text buffer and has no RETURN of LINE FEED characters (WS always splits buffers on a "RETURN" boundary). Under normal editing, this situation should not occur.
  514.  
  515.  
  516.  
  517. PROCEDURE WSShutDown;
  518.  
  519.  
  520. Shuts down WS and deallocates the code resource and any other memory structure it created.
  521.  
  522. Call this procedure once you are completely through with WS.
  523.  
  524. NOTE: You don't need to call WSShutDown if your application does an ExitToShell.
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531. PROCEDURE WSGetGlobals (VAR Globals:WSGlobals);
  532.  
  533.  
  534. Returns the current WSGlobals used by WS.
  535.  
  536.  
  537.  
  538.  
  539. PROCEDURE WSSetGlobals (Globals:WSGlobals);
  540.  
  541.  
  542. Sets the current globals to the values in Globals.
  543.  
  544. Warning:  WS will recognize any memory structures in Globals that you have created yourself; if so, it will deallocate its own.  However, once you have called WSSetGlobals the memory structures now "belong" to WS and will be disposed by WS at the appropriate time.
  545.  
  546.  
  547.  
  548.  
  549. FUNCTION WSColorEnable:Boolean;
  550.  
  551.  
  552. Returns whether the current system supports Color Quickdraw.  This function is provided for an easy way to detect a colored environment.  As result of TRUE indicates color.
  553.  
  554. Please note, however, that you can still set the color values (using WSSetColor) for various ranges of text in a non-colored environment -- it just won't display the color.
  555.  
  556.  
  557.  
  558.  
  559. PROCEDURE WSInitHooks (Hooks:WSHooksPtr);
  560.  
  561. Initalizes a WSHooks record to all NIL ProcPtrs.  The Hooks parameter points to a WSHooks record.
  562.  
  563. WSInitHooks is provided for an easy way to force the ProcPtr's to NIL from high-level languages.
  564.  
  565. Allocating & Disposing Handles
  566.  
  567.  
  568. FUNCTION WSNew (ViewRect:Rect; Bounds:LongRect; Flags:LongInt; Hooks:WSHooksPtr; Format:FormatPtr):WSHandle;
  569.  
  570.  
  571. Allocates a new WSHandle.
  572.  
  573. ViewRect is the display rectangle, in local coordinates. Bounds is taken as the predefined LongRect structure to allow movement greater than 32,768 pixels.
  574.  
  575. The difference between ViewRect and Bounds is that ViewRect is the clipped "window" area where the text can be seen, while Bounds defines both the top-left "scrolled" position of the text as well as the maximum text width boundaries for word-wrapping.
  576.  
  577.  
  578.  
  579.  
  580. Figure 2a and 2b show how ViewRect and Bounds work together:  by simply moving the Bounds rectangle's location the text is visually "scrolled."
  581.  
  582. The Flags  parameter sets certain attributes of the newly created WSHandle.  Currently there are three predefined bit settings for Flags:
  583.  
  584.  
  585. CONST    NoWrap =    1;    { If set, no text wrapping }
  586.     Deactive =    8;    { Inactive state }
  587.     ViewOnly =    16;    { No editing -- view-only }
  588.  
  589.  
  590. Hooks is an optional pointer to WSHooks (low-level routines) to be used by this WSHandle. If Hooks = NIL, the WSHandle uses the standard routines.
  591.  
  592. Format is a pointer to a format record that defines the beginning font, style, point size, and other text characteristics. If Format = NIL, the WSHandle's format defaults to the Application Font, 12 point plain text.
  593.  
  594.  
  595.  
  596.  
  597. FUNCTION WSText2New (Text:CharsHandle; ViewRect:Rect; Bounds:LongRect; Flags:LongInt; Hooks:WSHooksPtr; Format:FormatPtr):WSHandle;
  598.  
  599.  
  600. WSText2New works the same way as WSNew except it inserts Text data into the newly created WSHandle.
  601.  
  602. The parameters in addition to Text are identical to WSNew.
  603.  
  604. Note that a copy  is made of Text so you need to dispose the CharsHandle sometime after this call.
  605.  
  606. WSTest2New is the same as calling WSNew and then WSSetText except WSText2New provides a way to force the inserted text to specific stylations.
  607.  
  608.  
  609.  
  610.  
  611. PROCEDURE WSDispose (WS:WSHandle);
  612.  
  613.  
  614. Disposes a WSHandle's memory structures, including the WSHandle itself.
  615.  
  616. Use WSDispose once you are completely through with a WSHandle.
  617.  
  618.  
  619.  
  620.  
  621. PROCEDURE WSSetText (WS:WSHandle; TheText:CharsHandle);
  622.  
  623.  
  624. Disposes all previous text of WS and replaces it with a copy of TheText.
  625.  
  626. Note that a copy  is made of TheText -- you must dispose of TheText sometime after WSSetText.
  627.  
  628. Also note that the current text of WS is disposed -- if you need to insert  text without disposing what is already there, other routines are provided (such as a combination of WSText2New and WSPaste).
  629.  
  630.  
  631.  
  632.  
  633. FUNCTION WSGetText (WS:WSHandle):CharsHandle;
  634.  
  635.  
  636. Returns all text within WS as one contiquous CharsHandle.
  637.  
  638. The handle returned is a copy  of all the text.  If such a copy cannot be returned (due to memory restrictions), NIL is returned (after the global ErrorProc is called).
  639.  
  640. Note: WSGetText does not return any style information.  Use WSCopy for that purpose.
  641.  
  642.  
  643.  
  644.  
  645. FUNCTION WSGetSelText (WS:WSHandle):CharsHandle;
  646.  
  647.  
  648. Returns all text of the selection range in WS as one contiquous CharsHandle.
  649.  
  650. The handle returned is a copy  of all the text.  If such a copy cannot be returned (due to memory restrictions), NIL is returned (after the global ErrorProc is called).
  651.  
  652. WSGetSelText works exactly the same as WSGetText except only the selection range is returned. If there is no  selection range, the CharsHandle is still returned but it will be zero length in size.
  653.  
  654. Note: WSGetSelText does not return any style information.  Use WSCopy for that purpose.
  655.  
  656.  
  657.  
  658.  
  659. PROCEDURE WSGetBufInfo (WS:WSHandle; Position:Integer;
  660. VAR TBuf:TextBlock);
  661.  
  662.  
  663. Returns a TextBlock record in WS.  The Position parameter as a number from 0 to number of TextBlock records-1.  The wanted TextBlock is copied into TBuf.
  664.  
  665. If there is no such TextBlock (i.e., beyond range of array) then TBuf is initialized to all zeros.
  666.  
  667.  
  668.  
  669.  
  670. FUNCTION WSFindBuf (WS:WSHandle; Contains:LongInt;
  671. VAR TBuf:TextBlock):Integer;
  672.  
  673. Returns the TextBlock record containing the absolute offset Contains into text.
  674.  
  675. The TextBlock in WS containing the desired offset is copied into TBuf;  the function returns the array number of the block (the first one is zero).
  676.  
  677. WSFindBuf always returns a text block even if Contains is beyond the range of text;  therefore, passing some large arbitrary number causes the ending TextBlock record of the array to be returned.
  678.  
  679.  
  680.  
  681.  
  682. FUNCTION WSGetNumBufs (WS:WSHandle):Integer;
  683.  
  684.  
  685. Returns the number of TextBlock entries in WS.  This function will never return zero if WS is a valid WSHandle.
  686.  
  687.  
  688. Line Calculation & Display
  689.  
  690.  
  691. FUNCTION WSRebuild (WS:WSHandle; AllBufs:Boolean):LongInt;
  692.  
  693.  
  694. Recalculates as many text lines as necessary for WS to display properly.
  695.  
  696. WS was designed this way so many operations can be performed without  the delay of recalculation for each major change.  Hence, the application can control when and if there is a major recalculation.
  697.  
  698. Note, however, that if you end up displaying a WSHandle that requires calculation, WS is forced to recalculate prior to the display;  WSRebuild is provided in case you want to control that moment yourself.
  699.  
  700. If AllBufs = TRUE, the rebuild process considers all text buffers as necessary to do a full rebuild; if FALSE, only the text buffer at the start of the required rebuilding is calculated.  For speed-critical applications, the setting of TRUE may cause a major slow-down for very large blocks of text.
  701.  
  702. The function returns the offset of the first line record that needed recalculation, if any (this result can subsequently be passed to WSDisplay for maximum display speed);  if nothing was recalculated, the function returns -1 (minus one).
  703.  
  704.  
  705.  
  706.  
  707. PROCEDURE WSDisplay (WS:WSHandle; from:LongInt; Erase,
  708. ShowSel:Boolean);
  709.  
  710.  
  711. Displays the contents of WS to the current GrafPort.
  712.  
  713. The From parameter gives the starting offset of text to be displayed.  Note that this offset is obtainable from the WSRebuild function result and that a value of -1 will result in no display.
  714.  
  715. However, it is safe to pass zero in the From parameter since WS won't display anything outside of the view portion of WS.
  716.  
  717. The Erase parameter indicates whether the background is to be erased prior to display;  a value of TRUE causes the view area to erase.
  718.  
  719. ShowSel causes if caret and/or highlighting to display as well if the value is TRUE.
  720.  
  721.  
  722.  
  723.  
  724. PROCEDURE WSBitMapDisplay (WS:WSHandle; fromLine:LongInt; Txr:Integer; ShowSel:Boolean);
  725.  
  726.  
  727. Draws the contents of WS onto an offscreen bitmap then copies the contents to the current GrafPort.
  728.  
  729. Txr is the copy mode to be used for CopyBits.
  730.  
  731. WSBitMapDisplay works exactly the same as WSDisplay except its bit transfer avoids "flashing." It is, however, slightly slower than WSDisplay.
  732.  
  733.  
  734.  
  735. PROCEDURE WSSetCaret (WS:WSHandle; CaretState:Boolean);
  736.  
  737.  
  738. Turns the "caret" of WS on or off.
  739.  
  740. If CaretState = TRUE, the caret is turned on if not on already;  if FALSE, it is turned off if not off already.
  741.  
  742. CAUTION: Be sure to set the GrafPort where WS is normally drawn to; this routine does not set it for you.
  743.  
  744. Note:  Don't use WSSetCaret for activate and deactivate events -- use WSActivate and WSDeactivate instead.
  745.  
  746.  
  747.  
  748. Events, Mice and Keys
  749.  
  750.  
  751. PROCEDURE WSActivate (WS:WSHandle);
  752.  
  753. Causes WS to be an active WSHandle.
  754.  
  755. Use WSActivate in response to an activate event that belongs to a window containing WS.
  756.  
  757. An "active" WSHandle enables the blinking caret or the highlighted text display.
  758. If WS is already active, this call does nothing.
  759.  
  760. CAUTION: Be sure to set the GrafPort where WS is normally drawn to; this routine does not set it for you.
  761.  
  762.  
  763.  
  764.  
  765. PROCEDURE WSDeactivate (WS:WSHandle);
  766.  
  767.  
  768. Causes WS to be an inactive WSHandle.
  769.  
  770. Use WSDeactivate in response to a deactivate event that belongs to a window containing WS.
  771.  
  772. A "deactive" WSHandle disables the blinking caret or the highlighted text display.
  773.  
  774. If WS is already inactive, this call does nothing.
  775.  
  776. CAUTION: Be sure to set the GrafPort where WS is normally drawn to; this routine does not set it for you.
  777.  
  778.  
  779.  
  780.  
  781. PROCEDURE WSIdle (WS:WSHandle);
  782.  
  783.  
  784. Causes the "caret" to blink in WS.
  785.  
  786. Use WSIdle during your "event loop" to cause the caret to toggle.
  787.  
  788. If WS has been deactivated, WSIdle does nothing.
  789. CAUTION: Be sure to set the GrafPort where WS is normally drawn to; this routine does not set it for you.
  790.  
  791.  
  792.  
  793.  
  794. PROCEDURE WSKey (WS:WSHandle; Ev:EventRecord);
  795.  
  796.  
  797. Inserts a character in response to a KeyDown event.
  798.  
  799. Ev is the EventRecord taken exactly from the KeyDown event.
  800.  
  801. WSKey will insert the character from Ev at the current insertion point and redisplay the appropriate visual contents of tRect.
  802.  
  803. WSKey handles any situation for KeyEvent handling:  RETURN, backspace, TAB, and arrow keys. Word-wrapping and re-display is performed as needed;  scrolling, however, is not not.
  804.  
  805.  
  806. SCRIPT MANAGER NOTE:  The advise given in "Inside Mac" when using the Script Manager for non-Roman scripts of buffering keys until you have a valid character is not necessary with WS -- WSKey is handled correctly even for multi-byte characters.
  807.  
  808.  
  809.  
  810.  
  811. FUNCTION WSInsert (WS:WSHandle; Data:Ptr; Count:Integer):Boolean;
  812.  
  813.  
  814. Inserts Data of Count bytes into WS at the current insertion point.
  815.  
  816. The function returns TRUE if the text requires re-displaying.
  817.  
  818. WSInsert is mainly provided as an alternative way to insert characters if WSKey isn't used.
  819.  
  820.  
  821.  
  822.  
  823. PROCEDURE WSClick (WS:WSHandle; Ev:EventRecord; IdleProc:ProcPtr);
  824.  
  825.  
  826. Changes the insertion point in WS to match the exact mouse point in response to a MouseDown event and begins tracking the mouse movements.
  827.  
  828. Ev is the EventRecord taken exactly from a MouseDown event.
  829.  
  830. The mouse is tracked repeatedly, highlighting text as necessary, until the mouse is released. During the tracking, IdleProc is repeatedly called and is taken in the following format:
  831.  
  832. PROCEDURE MyIdleProc (WS:WSHandle; NewMouse:Point);
  833.  
  834. In the IdleProc, WS is the WSHandle involved.
  835.  
  836. NewMouse is the current mouse point, in local co-ordinates.
  837.  
  838. Note:  Be sure to set the correct GrafPort prior to WSClick and before returning from IdleProc. WS never  sets any GrafPort.
  839.  
  840. THE OTHER WS PROCEDURES AND FUNCTIONS CAN BE RE-ENTERED DURING THE IDLEPROC.  For instance, an application would often call WSScroll to perform automatic scrolling.
  841.  
  842. If WSScroll is called during the mouse tracking, WS is "smart" enough to know this and will adjust all internal values accordingly so automatic scroll will work correctly.
  843.  
  844.  
  845.  
  846. Changing Text Format
  847.  
  848.  
  849. NOTE: None of the formatting routines automatically re-display the text -- call WSDisplay or WSBitMapDisplay to update the screen contents.
  850.  
  851.  
  852.  
  853.  
  854. FUNCTION WSSetFont (WS:WSHandle; FontName:STR255):Boolean;
  855.  
  856.  
  857. Sets the font for WS to FontName.
  858.  
  859. If there is a selection range, than all characters selected become FontName;  otherwise, the new font becomes the current font for the next WSKey.
  860.  
  861. The font parameter is taken as a name  to be compatible with all future System releases.
  862.  
  863. If text needs to be redisplayed as a result of WSSetFont, this function returns TRUE.
  864.  
  865.  
  866.  
  867.  
  868. FUNCTION WSSetPoint (WS:WSHandle; PtSize:Fixed):Boolean;
  869.  
  870.  
  871. Sets the point size for WS to Point.  The point size is taken as a fixed  fraction to allow fractional point size for future enhancement; for the current version, set the high-order word to the point size and the low-order word to zero (or, another way, is to call FixRatio(pointSize,1) to obtain the proper "ratio").
  872.  
  873. If there is a selection range, than all characters selected become Point;  otherwise, the new point size becomes the text size for the next WSKey.
  874.  
  875. If text needs to be redisplayed as a result of WSSetPoint, this function returns TRUE.
  876.  
  877.  
  878.  
  879.  
  880. FUNCTION WSSetStyle (WS:WSHandle; TheStyle:Integer):Boolean;
  881.  
  882.  
  883. Sets the text face (style) for WS to TheStyle.  The style is taken as a 16-bit integer, the low-order byte is the Quickdraw style byte;  the high-order byte is reserved for additional "add-on" enhancements.
  884.  
  885. The way TheStyle affects text (or the next key insert) is as follows:
  886.  
  887. If TheStyle bits are all zero ("plain"), the text is forced to plain.
  888.  
  889. If a style in TheStyle does not hold true throughout the selected range of text, the entire selection range is set for that style;  if a style in TheStyle does hold true throughout, the style gets turned OFF.
  890.  
  891. If text needs to be redisplayed as a result of WSSetStyle, this function returns TRUE.
  892.  
  893.  
  894.  
  895.  
  896.  
  897. FUNCTION WSSetColor (WS:WSHandle; Color:RGBColor):Boolean;
  898.  
  899.  
  900. Sets the foreground color of text for WS to Color.  The color is taken as a Color Quickdraw RGBColor. Note that the color attribute gets stored in the format run even if the running environment does not support color.
  901.  
  902. If there is a selection range, than all characters selected become Color;  otherwise, the new color becomes the foreground for the next WSKey.
  903.  
  904. If text needs to be redisplayed as a result of WSSetColor, this function returns TRUE. (The function will never return TRUE if the running environment does not support color -- but the information gets stored in the format array).
  905.  
  906.  
  907.  
  908.  
  909. FUNCTION WSGetFont (WS:WSHandle; VAR FontName:STR255):Boolean;
  910.  
  911.  
  912. Returns the current font in WS.
  913.  
  914. FontName is set to the name of the font used.
  915.  
  916. If there is a selection range and the same font does not hold true throughout the range, the function returns FALSE and FontName gets set to a  zero length string.
  917.  
  918.  
  919.  
  920.  
  921. FUNCTION WSGetPoint (WS:WSHandle; VAR ThePoint:Fixed):Boolean;
  922.  
  923.  
  924. Returns the current point size in WS.
  925.  
  926. ThePoint is returned as a fixed fraction.
  927.  
  928. If there is a selection range and the same point size does not hold true throughout the range, the function returns FALSE and ThePoint gets set to zero.
  929.  
  930.  
  931.  
  932.  
  933. FUNCTION WSGetStyle (WS:WSHandle; VAR TrueStyle,
  934. AnyStyle:Integer):Boolean;
  935.  
  936.  
  937. Returns the current style(s) of WS.
  938.  
  939. TrueStyle and AnyStyle get set in the following way:  the bits set in TrueStyle correspond only to those styles within the selection range that hold true throughout;  AnyStyle's bits get set to those styles that appear anywhere  within the selection range.
  940.  
  941. You can always tell the difference between "plain" text and text which has no consistent styles -- AnyStyle will always be zero if the text is "plain."
  942.  
  943. The function returns TRUE only if TrueStyle and AnyStyle are identical.
  944.  
  945.  
  946.  
  947.  
  948. FUNCTION WSGetColor (WS:WSHandle; VAR Color:RGBColor):Boolean;
  949.  
  950.  
  951. Returns the current text foreground color in WS.
  952.  
  953. Color is set to the exact RGBColor if  the same color appears across the selection range.
  954.  
  955. If there is a selection range and the same color does not hold true throughout the range, the function returns FALSE and Color gets set to all zeros.
  956.  
  957.  
  958.  
  959.  
  960. PROCEDURE WSSetJust (WS:WSHandle; Just:Integer);
  961.  
  962.  
  963. Sets the text justification for WS.  The value passed in Just may be one of four:
  964.  
  965. 0 -- Left justify
  966. 1 -- Center justify
  967. 2 -- Right justify
  968. 3 -- Full justify
  969.  
  970. This procedure does not redisplay the screen -- you must call WSDisplay or WSBitMapDisplay to update the screen contents.
  971.  
  972.  
  973.  
  974.  
  975. FUNCTION WSGetJust (WS:WSHandle):Integer;
  976.  
  977.  
  978. Returns the current justification of WS.
  979.  
  980. Cut, Copy, Paste
  981.  
  982.  
  983.  
  984. FUNCTION WSCut (WS:WSHandle):Boolean;
  985.  
  986.  
  987. Deletes the selected text in WS.
  988.  
  989. If no text is selected, WSCut does nothing.
  990.  
  991. The function returns TRUE if WS needs recalculating as a result of the cut.
  992.  
  993.  
  994.  
  995.  
  996. FUNCTION WSCopy (WS:WSHandle):WSHandle;
  997.  
  998.  
  999. Returns a new WSHandle which is a copy of the selection range of WS.
  1000.  
  1001. The resulting WSHandle will require recalculation (WSRebuild) if you intend to display it.
  1002.  
  1003. If there is no selection range in WS, WSCopy still returns a WSHandle but it will contain empty text with the default format the same format as the source insertion point.
  1004.  
  1005. Use WSCopy instead of WSGetSelText if you wish to retain the formatting information.
  1006.  
  1007.  
  1008.  
  1009.  
  1010. FUNCTION WSPaste (srcWS,destWS:WSHandle):Boolean;
  1011.  
  1012.  
  1013. Inserts the contents of srcWS into destWS at the insertion point of destWS.
  1014.  
  1015. The source WSHandle is not altered.
  1016.  
  1017. The function returns TRUE if the resulting "paste" requires destWS to be recalculated prior to its re-display.
  1018.  
  1019. Note:  You can perform WSPaste as many times as you want even if destWS or srcWS require a "rebuild." Calling WSRebuild is only necessary for display.
  1020.  
  1021.  
  1022.  
  1023.  
  1024. PROCEDURE WSToScrap (WS:WSHandle);
  1025.  
  1026.  
  1027. Copies the entire text contents of WS to the external scrap.
  1028.  
  1029. WS is not altered;  it does not have to be rebuilt for this operation to work.
  1030.  
  1031. Tyically, WS is the handle returned from a WSCopy that you wish to place in the external scrap.
  1032.  
  1033.  
  1034.  
  1035.  
  1036. FUNCTION WSScrapToHandle (ViewRect:Rect; Bounds:LongRect;
  1037. Flags:LongInt; Hooks:WSHooksPtr;
  1038.  Format:FormatPtr):WSHandle;
  1039.  
  1040.  
  1041. Creates a new WSHandle using the TEXT contents from the external Scrap, if any.
  1042.  
  1043. The parameters are 100% identical to WSNew.
  1044.  
  1045. If the Scrap contains no TEXT data, WSScrapToHandle returns NIL.
  1046.  
  1047.  
  1048.  
  1049.  
  1050. FUNCTION WSCopyFormat (WS:WSHandle):FormatHandle;
  1051.  
  1052.  
  1053. Returns a FormatHandle which contains a format run of the selected text in WS.
  1054.  
  1055. If no text is selected (i.e., a "caret"), this function still returns a FormatHandle containing a single format record for that insertion point.
  1056.  
  1057. This routine is useful for setting up a format change "undo" (by first copying the formatting before applying changes). It is also useful for style sheet manipulation.
  1058.  
  1059. Note that WSCopyFormat returns a newly created handles --  the application must dispose it.
  1060.  
  1061.  
  1062.  
  1063.  
  1064. PROCEDURE WSApplyFormat (WS:WSHandle; Fmt:FormatHandle);
  1065.  
  1066. Changes the selection range of WS to the format(s) contained in Fmt. The text is not displayed.
  1067.  
  1068. Typically, Fmt is a handle obtained from a previous WSCopyFormat call (above). This function is useful for "undo" operations after a formatting change.
  1069.  
  1070.  
  1071.  
  1072. Selection Ranges & Scrolling
  1073.  
  1074.  
  1075.  
  1076. PROCEDURE WSGetSelect (WS:WSHandle; VAR bSel,eSel:LongInt);
  1077.  
  1078.  
  1079. Returns the current selection range of WS.  The bSel and eSel parameters are set to the beginning and ending selection ranges of text (relative to all text, not an individual buffer).
  1080.  
  1081.  
  1082.  
  1083.  
  1084. PROCEDURE WSSetSelect (WS:WSHandle; bSel,eSel:LongInt; Show:Boolean);
  1085.  
  1086.  
  1087. Sets the selection range of WS to bSel through eSel.  The values are taken as relative to all text in WS (not relative to an individual buffer).
  1088.  
  1089. If Show = TRUE, the new highlighting (or caret) is shown; otherwise no visual effect results.
  1090.  
  1091. PROCEDURE WSScroll (WS:WSHandle; h,v:LongInt);
  1092.  
  1093.  
  1094. Causes the contents of WS to "scroll",  moves the Bounds rect by h, v pixels and re-draws the scrolled area.
  1095.  
  1096. The movement for negative numbers is left and/or up;  positive numbers are down and/or right.
  1097.  
  1098. In effect, the contents of the view rectangle are scrolled.
  1099.  
  1100.  
  1101.  
  1102.  
  1103. PROCEDURE WSGetScrollState (WS:WSHandle; VAR h,v:LongInt);
  1104.  
  1105.  
  1106. Returns the current "scrolled" state of WS.
  1107.  
  1108. H returns the amount the contents are scrolled to the left and V returns the amount the contents are scrolled up.  Both numbers are positive.
  1109.  
  1110.  
  1111.  
  1112.  
  1113.  
  1114. PROCEDURE WSMove (WS:WSHandle; h,v:Integer);
  1115.  
  1116.  
  1117. Moves the entire display contents of WS by h and v pixels.
  1118.  
  1119. WS is not re-displayed.
  1120.  
  1121. This differs from WSScroll in that both ViewRect and Bounds are moved the same distances. Calling WSDisplay would display the contents at the new location.
  1122.  
  1123.  
  1124.  
  1125.  
  1126. FUNCTION WSSetBounds (WS:WSHandle; NewBounds:LongRect):Boolean;
  1127.  
  1128.  
  1129. Sets the Bounds rect for WS to NewBounds.
  1130.  
  1131. The function returns TRUE if the result forces WS to be rebuilt (in which case call WSDisplay, WSBitMapDisplay, or WSRebuild).
  1132.  
  1133. NOTE: WSSetBounds forces the scrolled state to 0,0 -- but does not redraw the contents.
  1134.  
  1135.  
  1136.  
  1137.  
  1138. PROCEDURE WSGrow (WS:WSHandle; h,v:Integer);
  1139.  
  1140.  
  1141. Expands the ViewRect by h and v pixels.
  1142.  
  1143. The right edge of ViewRect expands h pixels and the bottom expands v pixels.  The contents are not re-drawn.
  1144.  
  1145. PROCEDURE WSGetBounds (WS:WSHandle; VAR r:LongRect);
  1146.  
  1147.  
  1148. Returns the exact Bounds area which exactly encloses the visual text.
  1149.  
  1150. Note the the resulting LongRect is not necessarily identical to the tBounds field in WS -- WSGetBounds computes the bottommost pixel of the last line and sets r.Bottom accordingly.
  1151.  
  1152. This procedure is useful for determining the scrollable size of text.
  1153.  
  1154.  
  1155.  
  1156.  
  1157. PROCEDURE WSLine2Rect (WS:WSHandle; VAR R:LongRect; VAR Pix:Integer);
  1158.  
  1159.  
  1160. Returns display information about the currently selected line.
  1161.  
  1162. The LongRect R gets set to the rectangle which encloses the currently selected line exactly.
  1163.  
  1164. Pix gets set to the distance from the left edge of R, in pixels, of where the insertion point lives.
  1165.  
  1166. WSLine2Rect is useful for determining whether or not you need to automatically scroll the selected area to view.
  1167.  
  1168.  
  1169.  
  1170.  
  1171. PROCEDURE WSChar2Pt (WS:WSHandle; Offset:LongInt;
  1172. VAR Pos:tSelectPos);
  1173.  
  1174.  
  1175. Initializes a tSelectPos record that corresponds to a character location.
  1176.  
  1177. Offset is the position into text (relative to the entire text of WS).  Pos gets initialized to the exact line, text buffer, and "caret" position of Offset.
  1178.  
  1179.  
  1180.  
  1181.  
  1182. PROCEDURE WSPt2Char (WS:WSHandle; P:Point; VAR Pos:tSelectPos);
  1183.  
  1184.  
  1185. Initializes a tSelectPos record that corresponds to a local screen point.
  1186.  
  1187. WSPt2Char works exactly the same as WSChar2Pt except it is computed from a point instead of a character offset.
  1188.  
  1189.  
  1190.  
  1191.  
  1192. PROCEDURE WSChar2Word (WS:WSHandle; Offset:LongInt;
  1193. VAR b,e:tSelectPos);
  1194.  
  1195.  
  1196. Returns the starting and ending point of a full text word corresponding to a character location.
  1197.  
  1198. WSChar2Word works exactly the same as WSChar2Pt except two tSelectPos records are set: tSelectPos "b" is set to the first character of the word and "e" is set to the last character.
  1199.  
  1200.  
  1201.  
  1202.  
  1203. PROCEDURE WSPt2Word (WS:WSHandle; P:Point; VAR b,e:tSelectPos);
  1204.  
  1205.  
  1206. Returns the starting and ending point of a full text word corresponding to a screen point.
  1207.  
  1208. WSPt2Word works exactly the same as WSChar2Word except the two tSelectPos records are computed from a local-coordinate screen point.
  1209.  
  1210.  
  1211.  
  1212.  
  1213. PROCEDURE WSChar2Par (WS:WSHandle; Offset:LongInt;
  1214. VAR b,e:tSelectPos);
  1215.  
  1216.  
  1217. Returns the starting and ending point of a paragraph corresponding to a character location.
  1218.  
  1219. WSChar2Par works exactly the same as WSChar2Word except the result encompasses a paragraph.
  1220.  
  1221.  
  1222.  
  1223.  
  1224. PROCEDURE WSPt2Par (WS:WSHandle; P:Point; VAR b,e:tSelectPos);
  1225.  
  1226.  
  1227. Returns the starting and ending point of a paragraph corresponding to a screen point.
  1228.  
  1229. WSPt2Par works exactly the same as WSPt2Word except except the result encompasses a paragraph.
  1230.  
  1231.  
  1232.  
  1233. I/O Support
  1234.  
  1235.  
  1236.  
  1237. FUNCTION WSToHandle (WS:WSHandle):Handle;
  1238.  
  1239.  
  1240. Returns a newly created handle which contains a completely de-referenced, contiguous stream of data representing WS.  WSToHandle essentially concatenates all the internal memory structures in WS and creates a single memory structure which you can now save to a resource file or some other medium.
  1241.  
  1242. The source WSHandle is not altered.
  1243.  
  1244. If this routine fails (due to insufficient memory), NIL is returned.
  1245.  
  1246. CAUTION: WS supports fantastically large editing structures -- if your WSHandle is potentially very large (e.g., megabytes), you should create some other way of saving and retrieving data structures to avoid an out-of-memory situation.
  1247.  
  1248.  
  1249.  
  1250.  
  1251.  
  1252. FUNCTION HandleToWS (H:Handle):WSHandle;
  1253.  
  1254.  
  1255. Reverses the process from WSToHandle. The function returns a newly created WSHandle.
  1256.  
  1257. H is the Handle which was previously obtained from WSToHandle.  If this function fails (due to insufficient memory), HandleToWS returns NIL.
  1258.  
  1259.  
  1260.  
  1261.  
  1262. FUNCTION WSPrint (WS:WSHandle; Position:LongInt; Dest:Rect):LongInt;
  1263.  
  1264.  
  1265. Draws the contents of WS beginning at text offset Position for as many lines that will completely fit in Dest.  The drawing occurs to the current GrafPort (which is typically a printer port).
  1266.  
  1267. The first line in WS which contains offset Position is "pinned" to the top-left of Dest (which is to say Dest is used in place of  tBounds).  That first line and all subsequent text that completely fits into Dest is drawn relative to the top-left of Dest;  text which falls below Dest.Bottom, even by 1 pixel,  is not drawn.
  1268.  
  1269. Essentially, WSPring ignores the current "scrolled" state and pins itself to a page rectangle.
  1270.  
  1271. The function returns the beginning offset of the first text that did not draw (becuase it did not completely fit in Dest);  if ALL text from Position to the end of text was drawn, the function returns -1.
  1272.  
  1273. Note that to print a whole "document" you would call WSPrint with Position set to zero, Dest set to the printer port's PageRect, then make subsequent calls to WSPrint with Position = function result until the function returns -1.
  1274.  
  1275. IV: Advance Techniques
  1276.  
  1277.  
  1278. Customizing Text: UserStyles
  1279.  
  1280.  
  1281. Every format record (an element in an array defining a text section's font, style, point size, and color) has an optional pointer to a set of procedure pointers:
  1282.  
  1283.  
  1284. UserStylesPtr = ^UserStyles;
  1285. UserStyles = RECORD
  1286. hMeasureText:ProcPtr;    { Text widths measurement proc }
  1287. hDrawText:ProcPtr;    { Text drawing proc }
  1288. hFmtDelete:ProcPtr;    { About to delete a FormatRec }
  1289. hFontInfo:ProcPtr;    { Get font info }
  1290.     END;
  1291.  
  1292.  
  1293. Each function contained in this array of routines is described in detail under the section, "Low-Level Hook Routines," -- the first four functions of UserStyles and the low-level hooks are 100% identical except that each routine for a UserStyle is called only  for that particular section of text while the low-level hooks are called for all  situations.
  1294.  
  1295. Any of the fields that are non-NIL are considered procedure pointers and get called at the appropriate time;  hence you can pick and choose which items to use by setting the unneeded routines to NIL.
  1296.  
  1297.  
  1298.  
  1299. UserStyle Maintenance
  1300.  
  1301.  
  1302.  
  1303. FUNCTION WSSetUserStyle (WS:WSHandle; UserProcs:UserStylesPtr; AndMask,OrMask:LongInt:Boolean;
  1304.  
  1305.  
  1306. Sets the insertion point (or selection range) to a UserStyles format. In addition to the UserStylesPtr, the text format assumes the characteristics of the font, style, point size, etc. of the current insertion point or selection range.
  1307.  
  1308. The UserProcs parameter points to a UserStyles record which is fully explained under "Low Level Hooks" and "User Styles" sections.  Elements of UserProcs that are NIL are not called.
  1309.  
  1310. AndMask and OrMask can be anything the application chooses; it is placed in the UserSpace field of the FormatRec that gets inserted into WS and works as follows:  The value of AndMask gets logically AND'd to UserSpace (either source or destination bit is a zero the result is zero) and the OrMask gets logically OR'd to UserSpace (either source or destination bit is a one the result is one).
  1311.  
  1312. The result of WSSetUserStyle is exactly the same as any other text formatting change except the various functions in UserProcs are called for text measurement, display and deletion.  The end result is "customized" text styles and formatting.
  1313.  
  1314. The function returns TRUE if text requires re-displaying.
  1315.  
  1316. Note that if your UserStyles require special data imbedded in the text stream (such as a picture handle) you can accomplish this by immediately calling WSInsertText after WSSetUserStyle. When doing so, the inserted "text" assumes the characteristic of the UserStyle.
  1317.  
  1318.  
  1319.  
  1320.  
  1321. FUNCTION WSFindUserStyle (WS:WSHandle; AndMask,OrMask:LongInt; 
  1322. VAR Position,Count:LongInt; VAR Fmt:FormatRec):Integer;
  1323.  
  1324.  
  1325. Returns the relative position into text of a UserStyle, if any.
  1326.  
  1327. The search for a UserStyle begins at Position, walks through the format run until it finds a UserStyle  whose UserSpace field meets the criteria of AndMask and OrMask, or comes yo the end of the format run, whichever comes first.
  1328.  
  1329. For each potential format record containing a UserStyle (UserProcs field of the format record <> NIL), a comparison is made with AndMask and OrMask as follows:  UserSpace is first ANDed with AndMask then compared to OrMask;  if a match is made with OrMask, WSFindUserStyle returns with that format record and sets Position and Count to the relatitive text position and number of bytes affected by the format record, respectively. Fmt is also initialized to the full FormatRec.
  1330.  
  1331. Note that you can "walk through" all UserStyles regardless of their UserSpace contents by setting both AndMask and OrMask to zero -- if the bits in the UserSpace get ANDed with all zeros, the result is zero and thus it will always match with OrMask.  You would eventually, of course, receive a function result of -1 once there were no more UserStyle records after Position.
  1332.  
  1333. If a UserStyle is found, the function returns the array element of Fmt in the format run array (the first element = 0); if not found, the function returns -1 and the values of Position, Count, and Fmt are uncertain.
  1334.  
  1335.  
  1336.  
  1337.  
  1338. FUNCTION WSSetUserSpace (WS:WSHandle; AndMask,
  1339. OrMask:LongInt; Only4User:Boolean):Boolean;
  1340.  
  1341.  
  1342. Sets the UserSpace field(s) of the format records for the current insertion point or selection range of WS.
  1343.  
  1344. AndMask and OrMask set the UserSpace by first ANDing the AndMask then ORing the OrMask. For merely forcing the UserSpace to a new value set AndMask to zero (which will cause the previous UserSpace to clear) and OrMask to the desired value (which would then set UserSpace to the same value in OrMask).
  1345.  
  1346. If Only4User = TRUE, only the format records that contain UserStyles (the UserProcs field in the format record <> NIL) are affected;  if FALSE, then all  format records within the selection range are affected.
  1347.  
  1348. If WS merely has an insertion point (beginning selection = ending selection), no changes to UserSpace take effect until the next WSKey or WSInsert.
  1349.  
  1350.  
  1351.  
  1352.  
  1353. FUNCTION WSGetUserSpace (WS:WSHandle;
  1354. VAR AllSpaces,AnySpaces:LongInt):LongInt;
  1355.  
  1356.  
  1357. Returns the values in the UserSpace field(s) of the current selection range of WS.
  1358.  
  1359. AllSpaces and AnySpaces get set in the following way: If any bit of the 32-bit UserSpace within the selection range is a "1" and that same bit holds true through the selection range as a "1" gets set in AllSpaces, while if any bit is a "1" within any  UserSpace field of the selection range the corresponding bit gets set.
  1360.  
  1361. The function itself returns a copy of the first UserSpace of the selection range.  Note that AllSpaces, AnySpaces and and function result will all be equal if WS contains an insertion point (no selection range).
  1362.  
  1363. WSGetUserSpace is useful if you are using UserStyles and want to treat the UserSpace field as an extension of text styles.
  1364.  
  1365.  
  1366. Additional Format Run Support
  1367.  
  1368.  
  1369. The following routines are useful for directly manipulating FormatRecs (a WS format run) in ways not covered by the conventional WSSetFont, WSSetStyle, etc.:
  1370.  
  1371.  
  1372.  
  1373. FUNCTION WSFindFormatRec (WS:WSHandle; VAR Position,Count:LongInt;
  1374. VAR Fmt:FormatRec):Integer;
  1375.  
  1376.  
  1377. Finds and returns the first format record in WS corresponding to text position Position.
  1378.  
  1379. Upon return, Position gets updated to the exact text position of the format, Count is initialized to the number of bytes of text affected by this format and Fmt is initialized to the FormatRec itself.
  1380.  
  1381. The function itself returns the array element number of the format record (first one = 0).
  1382.  
  1383. Note that WSFindFormatRec will always return a format record even if Position is beyond the range of text.  The last (ending) format record can be known by examining Position + Count -- if Position + Count = length of all text (which is the tLength field in the WS record) the last format record has been given.
  1384.  
  1385. WSFindFormatRec is useful for "walking through" the format run of a WSHandle:  by initially setting Position to zero, make repetitive calls to WSFindFormatRec, each time adding Count to Position before the next subsequent call and terminating when Position + Count = length of all text.
  1386.  
  1387.  
  1388.  
  1389.  
  1390. PROCEDURE WSSetFormatRec (WS:WSHandle; VAR Fmt:FormatRec; Element:Integer);
  1391.  
  1392.  
  1393. Replaces the contents of a format record with the contents of Fmt.
  1394.  
  1395. The precise format record replaced is given in Element which is an array position of WS's format run. The first element is 0, the second element is 1, and so on.
  1396.  
  1397. Note that Element can be obtained for a specific format record from the function result of WSFindFormatRec, above.
  1398.  
  1399. WSSetFormatRec is useful for initializing a previously saved WS structure that requires global format changes (such as new UserStyle hooks or changes to fonts that no longer exist in the system).
  1400.  
  1401.  
  1402.  
  1403.  
  1404. PROCEDURE WSFixFonts (WS:WSHandle; OldFont,NewFont:STR255;
  1405. OldSize,NewSize:Fixed);
  1406.  
  1407.  
  1408. Forces different fonts and/or point sizes throughout WS by substituting OldFont with NewFont and/or OldSize with NewSize.
  1409.  
  1410. WSFixFonts has been mainly provided to fix a situation where certain fonts no longer exist and need to be substituted by another;  similarly, certain point sizes may have been unscaled yesterday but removed from the System today causing an older WSHandle to word-wrap incorrectly.
  1411.  
  1412. When this procedure is called, WS searches for all format records contain both OldFont and OldSize and, if found, substitutes NewFont and NewSize.
  1413.  
  1414. However, if OldFont is an empty string (length zero) it is considered a "wild card" and causes only the point size to be checked;  concurrently, if OldSize = 0, it is considered a "wild card" and only OldFont is checked.
  1415.  
  1416. Also, if either NewFont or NewSize is zero length or zero, respectively, it is not substituted. Hence you may pass various combinations to affect only fonts, only styles, or both.
  1417.  
  1418.  
  1419.  
  1420. Low-Level "Hook" Routines
  1421.  
  1422.  
  1423. As mentioned previously, each WSHandle contains a predefined variable, a WSHookPtr. This is a pointer to several low-level procedure pointers in which the application can intercept for purposes of customized text displays, word-wrapping, etc.
  1424.  
  1425. A similar set of hooks, UserStyles, can be used as part of a format record itself causing portions of text to be sectioned off and customized.
  1426.  
  1427. In short, the application can "tap in" to WS's most basic functions:  WS will make a call to the hook addresses at the appropriate moment, giving the application a change to inspect and/or change the outcome.
  1428.  
  1429.  
  1430. The variable WSHooksPtr  is predefined as follows:
  1431.  
  1432. WSHooksPtr = ^WSHooks;
  1433. WSHooks = RECORD
  1434. hMeasureText:ProcPtr;    { Text widths measurement proc }
  1435. hDrawText:ProcPtr;    { Text drawing proc }
  1436. hFmtDelete:ProcPtr;    { About to delete a FormatRec }
  1437. hFontInfo:ProcPtr;    { Get FontInfo }
  1438. hWordBreak:ProcPtr;    { Need word break point }
  1439. hTabWidth:ProcPtr;    { Return width of TAB }
  1440. hTabDraw:ProcPtr;    { Tab is "drawn" }
  1441. hMaxWidth:ProcPtr;    { Return maximum line width }
  1442. hPreCalc:ProcPtr;    { Prepare for line calculation }
  1443. hPostCalc:ProcPtr;    { Finish line calculation }
  1444. hDoneCalc:ProcPtr;    { WS thinks it is done with calc.}
  1445. hSmartScroll:ProcPtr;    { Needs to scroll for CR or backspace}
  1446. hPt2Line:ProcPtr;    { Return a line containing a point}
  1447. hSelectRgn:ProcPtr;    { Return a selection region }
  1448. hGetBuf:ProcPtr;    { Get a text buffer }
  1449. hNewBuf:ProcPtr;    { Create a new text buffer }
  1450. hDeleteBuf:ProcPtr;    { Delete a buffer }
  1451. hPreDraw:ProcPtr;    { Called before drawing a line }
  1452. hPostDraw:ProcPtr;    { Has just drawn proc }
  1453. hrsvd1:ProcPtr;    { - reserved - }
  1454. hrsvd2:ProcPtr;    { - reserved - }
  1455. hrsvd3:ProcPtr;    { - reserved - }
  1456. hrsvd4:ProcPtr;    { - reserved - }
  1457. END;
  1458.  
  1459.  
  1460. If any of the above set of procedure pointers are non-NIL the routine is called at the appropriate moment. The basic idea is to allow an external application intercept the core routines (or completely replace them) to obtain customize objects and display.
  1461.  
  1462. To do so, place a pointer to a routine in the appropriate WSHooks field(s), set the hook fields you do not  need to use to NIL and place a pointer to the WSHooks record into the tProcs field of the WSHandle you wish to affect.
  1463.  
  1464. The same is true for UserStyles except the pointer to the hooks record is passed via WSSetUserStyle.
  1465.  
  1466.  
  1467. The following is a description of each hook function:
  1468.  
  1469. hMeasureText.  Called whenever WS needs to measure the text width of one or more characters.  It is taken as:
  1470.  
  1471.  
  1472. FUNCTION hMeasureText (WS:WSHandle; VAR Fmt:FormatRec; Txt:Ptr; Count, Slop:Integer; Widths:Ptr):Boolean;
  1473.  
  1474.  
  1475. WS is the current WSHandle containing the text to be measured.
  1476.  
  1477. Txt is a pointer to the text and Count is the number of bytes to be measured.
  1478.  
  1479. Fmt is the current FormatRec of the text's style attributes (Font, style, etc.).  Note that the current Font, style, and point size will also be set in the current GrafPort upon entry.
  1480.  
  1481. The Slop parameter is the amount of distance to expand the text (such as full justification), in pixels. Note that this value will be zero if the text is not fully justified.
  1482.  
  1483. The Widths parameter is a pointer which your application must fill with consecutive integer character positions, in pixels. The first  integer is always the position of the zeroth character and should always be zero; the second integer must be the relative pixel position of the next character, and so on.
  1484.  
  1485.  The result placed in Widths is 100%  identical to Quickdraw's MeasureText result (or Script Manager's MeasureJust result) so consult Inside Macintosh for more details.
  1486.  
  1487. The hMeasureText function will never pass text which crosses multiple format boundaries; it will also never pass text containing more than one control character.  Rather, WS partitions such portions of text and makes multiple hMeasureText calls.  In any case, the current Font, Style, point size and color are set in the current GrafPort prior entering your function.
  1488.  
  1489. If the function returns TRUE then WS uses the information in Widths;  if FALSE, WS ignores the values in Widths and calculates the text width using its own procedure.
  1490.  
  1491.  
  1492.  
  1493. hDrawText.  Called before WS draws any text. It is taken in the form of:
  1494.  
  1495.  
  1496. FUNCTION hDrawText (WS:WSHandle; Txt:Ptr; VAR Fmt:FormatRec; Count,Slop,Ascent,Descent:Integer):Boolean;
  1497.  
  1498.  
  1499. WS is the WSHandle being displayed. Txt points to the text to be drawn while Fmt is the current font, text face, point size and color.
  1500.  
  1501. Upon entry, the appropriate text format is set in the current GrafPort;  the exact pen position is also pre-set to the location to begin drawing.
  1502.  
  1503. Count and Slop are the byte count and extra distance to be made up for full justification, respectively.
  1504.  
  1505. Ascent and Descent define the total height of the current line -- Ascent is the distance above the current vertical pen position while Descent is the distance below the vertical pen. Hence, currentPen.V-Ascent = text line's "top" and currentPen.V+Descent = current text line's "bottom."
  1506.  
  1507. If the application uses hDrawText, it must update the GrafPort's pen position.
  1508.  
  1509. If TRUE is returned as the function result, WS assumes the text has been drawn;  for FALSE, WS goes ahead and draws the text in the standard way.
  1510.  
  1511.  
  1512. NOTE: THE CURRENT GRAFPORT DURING THE EXECUTION OF HDRAWTEXT IS NOT NECESARILY THE GRAFPORT YOU HAD SET BEFORE CALLING WS ROUTINES -- IT IS OFTEN TO AN OFFSCREEN BITMAP.
  1513.  
  1514.  
  1515.  
  1516.  
  1517. hFmtDelete.  Called prior to a FormatRec (format run element).  It is taken in the form of:
  1518.  
  1519.  
  1520. PROCEDURE hPreDelete (WS:WSHandle; Element:Integer;
  1521. VAR Fmt:FormatRec);
  1522.  
  1523.  
  1524. WS is the WSHandle containing the text to be deleted. A FormatRec is deleted whenever it is no longer needed due to text deletion.  This situation can occur not only from a "cut" operation but also a backspace.
  1525.  
  1526. Element is the array element of the FormatRec in question, while Fmt is the FormatRec itself.
  1527.  
  1528. The main usage for hFmtDelete is to purge any special structures you might have created for customized "text" (such as picture data).
  1529.  
  1530. NOTE:  You must never actually delete the FormatRec -- hFmtDelete merely lets you examine the FormatRec and perform any cleanup actions that might be needed.
  1531.  
  1532. Warning: You may not re-enter any WS procedure and function during this call.
  1533.  
  1534.  
  1535.  
  1536.  
  1537. hFontInfo.  Called to get the current Font's height (ascent, descent, and leading values). It is taken in the form of:
  1538.  
  1539.  
  1540. PROCEDURE hFontInfo (WS:WSHandle; VAR Fmt:FormatRec; Position:LongInt; VAR fInfo:FontInfo);
  1541.  
  1542.  
  1543. WS is the current WSHandle.
  1544.  
  1545. Fmt is the precise Font, style, and point size of the text in question;  note that this font, style and size is also set in the current GrafPort upon entry.
  1546.  
  1547. Position is the absolute offset into text that is being measured (not relative to the current TextBlock).
  1548.  
  1549. Prior to entry, WS makes the standard GetFontInfo call to Quickdraw initializing the fInfo parameter;  user of this hook may change its values (such as changing the font leading or height).
  1550.  
  1551.  
  1552.  
  1553.  
  1554. hWordBreak.  Called after a word did not successfully fit on the end of a line.  This function is provided as a means for the application to perform hyphenation or other such word breaking. It is taken in the form of:
  1555.  
  1556. FUNCTION hWordBreak (WS:WSHandle; Txt,Widths:Ptr; Count,
  1557. RemWidth:Integer):Integer;
  1558.  
  1559.  
  1560. WS is the WSHandle containing the line being calculated.
  1561.  
  1562. Txt is a pointer to the first character of the word that does not fit on the line, while Count is the number of bytes that comprise the word.  The "word" will always consist of non-breaking characters and will contain no spaces or control characters.
  1563.  
  1564. Widths is a pointer to an array of integers containing precise character widths for each character beginning with the first character of Txt. (Note: this is not the same as the result from MeasureText -- each integer in this table corresponds to exact character widths, including kerning, as opposed to accumulated character positions).
  1565.  
  1566. The RemWidth parameter contains the maximum amount of space, in pixels, remaining in the line.  The idea is for the application to decide if there is a way to hyphenate the word and make it fit, including the width of the hyphen character.
  1567.  
  1568. The function must return an offset of where to break the word;  note that a result of ZERO implies that the word should not be broken but merely "wrap" to the next line;  any other number will cause the word to break and a hyphenation symbol drawn (the hyphenation symbol used is contained in the Hyphen field of the Globals record -- see Global Parameters).
  1569.  
  1570.  
  1571.  
  1572.  
  1573. hTabWidth.  Called to get the "width" of a TAB character. The function is called to obtain the amount of distance, in pixels, that should be added to the current text width position.
  1574.  
  1575. For example, when WS is measuring text widths, a TAB character is typically computed dynamically depending on the previous character's pixel position.
  1576.  
  1577. The function is taken in the form of:
  1578.  
  1579.  
  1580. FUNCTION hTabWidth (WS:WSHandle; Txt,Widths:Ptr; Count,
  1581. Width:Integer):Integer;
  1582.  
  1583.  
  1584. WS is the WSHandle containing the text with a TAB character.
  1585.  
  1586. Txt is a pointer to the TAB character in the text and the bytes that follow the TAB. Thus it is possible to compute, say, a decimal or right-justified TAB by examining the adjacent characters.
  1587.  
  1588. The Count parameter is the remaining bytes of text either for the current line or the current text buffer;  in either case, there will always be enough characters to compute a non-left justified TAB.
  1589.  
  1590. Widths is a pointer to an array of integers in which each entry contains the consecutive character widths for each character in Txt;  the 0th entry is the width of the first character, the next entry is the width of the second character, and so on. Note that this is not  the same as the width table from MeasureText -- the result of MeasureText  contains consecutive character positions, while Widths, in this function, contain consecutive widths.  Each entry in Widths is guaranteed to be precise according to the text's multiple fonts, styles, and point size. 
  1591.  
  1592. The Width parameter contains the sum total text width of the text before  the TAB character. This value will always be the aggregate character widths from the beginning of a text line up to, but not including, the TAB character.  Note that if this is being called during display  of text, the Width parameter contains the current pen position minus the starting pen position of the current line.
  1593.  
  1594. The function should return the wanted width the of TAB character. However, a negative result causes WS to use the default tab spacing.
  1595.  
  1596.  
  1597. WARNING: THE POINTER TO TEXT IS NOT NECESSARILY LOCKED FROM RELOCATING IN MEMORY -- IF YOU DO ANYTHING THAT MIGHT COMPACT THE HEAP THE POINTER TO TEXT WILL BECOME INVALID. THE CHARACTER WIDTHS ARE GIVEN TO YOU DURING THE EXECUTION OF HTABWIDTH SO YOU NORMALLY DON'T HAVE TO MAKE ANY CALLS THAT WILL LOAD RESOURCES (e.g., TextFont, TextWidth, etc.).
  1598.  
  1599.  
  1600.  
  1601.  
  1602. hTabDraw.  Called right after a TAB character is positioned on the screen. The hTabDraw hook is useful for drawing "leaders."  It is taken in the form of:
  1603.  
  1604.  
  1605. PROCEDURE hTabDraw (WS:WSHandle; NewPen:Point; Ascent,Descent:Integer);
  1606.  
  1607.  
  1608. WS is the current WSHandle.
  1609.  
  1610. NewPen is the exact pen position, in local co-ordinates, that the next text drawing will take place after  a TAB character (the actual "width" between the end of the last text and the pen position had been previously been obtained from hTabWidth, above).  The ending pen position of the previously drawn text is the pen position of the current GrafPort.
  1611.  
  1612. In other words, the total distance between the end of the last text and the current TAB mark is NewPen.H minus current GrafPort's horizontal pen position.
  1613.  
  1614. Ascent and Descent are the distances above and below the current vertical pen position, respectively.
  1615.  
  1616.  
  1617.  
  1618.  
  1619. hMaxWidth.  Called to obtain the maximum width for a given line of text. This is always used to determine word-wrapping when a line built and is called first before taking any further line calculation (text measurement) actions.  It is taken in the form of:
  1620.  
  1621.  
  1622. FUNCTION hMaxWidth (WS:WSHandle; VAR TBuf:TextBlock; Position:Integer):Integer;
  1623.  
  1624.  
  1625. WS is the WSHandle containing the line to be computed.
  1626.  
  1627. TBuf is a TextBlock record containing the text and line array for the line.
  1628.  
  1629. Position is the array element in the line array for the line about to be calculated (the first element is zero).
  1630.  
  1631. The function must return the maximum width of the line, in pixels.  However, a result of ZERO causes WS to use the default maximum (which is the width of the tBounds area of WS).
  1632.  
  1633. The hMaxWidth function is called before hPreCalc, below; it can also be called on any other occassion requiring the maximum distance a given line can be.
  1634.  
  1635. hPreCalc. Called just before text measurement for line calculation.  The purpose of hPreCalc is to allow the application to interrogate the line's starting structure before calculation begins and making any necessary changes for customized display.  The function is taken in the form of:
  1636.  
  1637.  
  1638. FUNCTION hPreCalc (WS:WSHandle; VAR TBuf:TextBlock; Position:Integer;
  1639. VAR Line:LineRec):Boolean;
  1640.  
  1641.  
  1642. WS is the WSHandle containing the line about to be calculated.
  1643.  
  1644. TBuf is a TextBlock record containing the text and line array for the line.
  1645.  
  1646. Position is the array element in the line array for the line about to be calculated (the first element is zero).
  1647.  
  1648. The Line parameter contains the initial values for the line to be calculated;  its fields are initialized exactly the same as hMeasureText, above.
  1649.  
  1650. Note that the application can change any of the values of Line (or even Offset) to get the desired result;  WS will use whatever exists in Line after this function returns.
  1651.  
  1652. If the function result is TRUE, WS continues and calculates the line (computing text widths, calling hMeasureText, etc.);  if the result is FALSE, WS assumes the application did its own calculation and thus stores Line into the line array as-is.
  1653.  
  1654.  
  1655.  
  1656.  
  1657. hPostCalc.  Called after a line is completely calculated. The purpose of this function is to let the application make any additional changes to the line entry before it is placed into the line array. It is taken in the form of:
  1658.  
  1659.  
  1660. FUNCTION hPostCalc (WS:WSHandle; VAR TBuf:TextBlock; Position:Integer;
  1661. VAR Line:LineRec):Boolean;
  1662.  
  1663.  
  1664. The parameters and their meanings are 100% identical to hPreCalc.
  1665.  
  1666. A function result of TRUE tells WS to "accept" this line and place it into the line array; a result of FALSE is taken as a "rejection," in which case the line is re-calculated (beginning with hMaxWidth and hPreCalc).
  1667.  
  1668.  
  1669.  
  1670.  
  1671. hDoneCalc. Called when WS thinks it can quit calculating lines.
  1672.  
  1673. The function is taken in the form of:
  1674.  
  1675.  
  1676. FUNCTION hDoneCalc (WS:WSHandle; VAR TBuf:TextBlock;
  1677. VAR Position:Integer; VAR Line:LineRec):Boolean;
  1678.  
  1679.  
  1680. WS is the current WSHandle;  TBuf is the current TextBlock record containing the line array.
  1681.  
  1682. The Position value is the array element of the line which WS thinks does not need recalculating.
  1683.  
  1684. The Line parameter contains the line record WS thinks is not necessary to recalculate. Note that application can change fields as needed.
  1685.  
  1686. This function is called whenever WS has only recalculated a portion of the line array but not all, considering that the subsequent lines do not change lengths or word-wrapping (but may  change vertical positions) so no further calculation "crunch" is necessary under normal circumstances.
  1687.  
  1688. If the function returns TRUE, then the application "agrees" with WS that lines need no further calculation;  a result of FALSE tells WS to continue calculating anyway.
  1689.  
  1690. If WS does  continue calculation (by receiving a FALSE result) it will pick up the next line according to the values in Position and Line -- thus you can force it to continue calculating somewhere else other than the line originally passed in the function.
  1691.  
  1692. A typical usage of hDoneCalc is for word-wrapping within "columns" -- while WS assumes a single rectangle for line calculation, it may be required to force new measurements for wrapping to some other area.
  1693.  
  1694.  
  1695.  
  1696. hSmartScroll -- Called whenever WS wants to scroll lines up or down on the screen to create a fast response to a RETURN key or backspacing a RETURN character.
  1697.  
  1698. Whenever WS detects a situation where lines simply shift up or down, and no new word-wrapping is required, it speeds up the process by merely scrolling the appropriate area of the screen and re-drawing the affected area(s).
  1699.  
  1700. The function is called before  doing this action. It is taken in the form of:
  1701.  
  1702.  
  1703. FUNCTION hSmartScroll (WS:WSHandle; VAR TopLine:LineRec;
  1704. VAR Amount:Integer; VAR Box:Rect; Upd:RgnHandle):Boolean;
  1705.  
  1706.  
  1707. WS is the WSHandle involved.
  1708.  
  1709.  TopLine is a copy of the first line affected (this line and all subsequent lines will "scroll").
  1710.  
  1711. Amount is the distance it will scroll, in pixels. Negative values scroll UP and positive values scroll down. Note that the application can change this value if necessary.
  1712.  
  1713. The Box parameter defines the area of the screen to be scrolled (in which a ScrollRect will be performed).  Note that the application can change this rectangle if necessary.
  1714.  
  1715. If the application does its own scrolling it should set Upd to the area to update the screen (which is identical to the RgnHandle passed in ScrollRect).
  1716.  
  1717. If the function returns TRUE, WS does no scrolling but does update the screen clipped to the Upd RgnHandle;  if FALSE is passed, WS goes ahead with the standard scrolling.
  1718.  
  1719.  
  1720.  
  1721.  
  1722. hPt2Line. Called to find a line array entry containing a specific point.  This function is always called in response to a WSClick (and subsequent mouse tracking) to locate which line the mouse is clicked on.  It is taken in the form of:
  1723.  
  1724. FUNCTION hPt2Line (WS:WSHandle; P:Point;
  1725. VAR TBPosition,LinePosition:Integer):Boolean;
  1726.  
  1727.  
  1728. WS is the WSHandle involved.
  1729.  
  1730. P contains the point, in local co-ordinates from which to find the line that contains it.
  1731.  
  1732. TBPosition and LinePosition should return with the TextBlock and line array elements, respectively (the lowest element = 0).
  1733.  
  1734. If the function returns TRUE, WS uses the information in TBPosition and LinePosition to continue processing the mouse-click;  if FALSE is the result, WS searches for the line itself with the default routine(s).
  1735.  
  1736.  
  1737.  
  1738.  
  1739. hSelectRgn.  Called to obtain the area of the screen to be highlighted (inverted). It is taken in the form of:
  1740.  
  1741.  
  1742. FUNCTION hSelectRgn (WS:WSHandle; VAR bSel,eSel:tSelectPos, Sel:RgnHandle):Boolean;
  1743.  
  1744.  
  1745. WS is the WSHandle involved
  1746.  
  1747. The bSel and eSel define the areas to be inverted; both are tSelectPos records which contain the relative text, line, and "caret" positions if a selection range.  Note that these are not necessarily the entire selection range of WS -- in mouse tracking, for instance, they will involve small section of text.
  1748.  
  1749. If a selection region is indeed determined, the application should fill Sel with the appropriate shape (a group of rectangles, for instance).
  1750.  
  1751. If the function returns TRUE, WS inverts the region, otherwise it creates in own selection region in the standard way.
  1752.  
  1753.  
  1754.  
  1755.  
  1756. hGetBuf. Called to obtain a text buffer.  This hook is typically used for memory management and/or disk buffering of text. It is always called after locating a specific TextBlock in the text buffer array but before using any of its contents. It is taken in the form of:
  1757.  
  1758.  
  1759. FUNCTION hGetBuf (WS:WSHandle; Position:Integer;
  1760. VAR TBuf:TextBlock):Boolean;
  1761.  
  1762.  
  1763. WS is the WSHandle containing the text buffer.
  1764.  
  1765. Position is the array element of the TextBlock (first element = 0);
  1766.  
  1767. TBuf is the TextBlock record that WS wants to use.
  1768.  
  1769. This procedure is useful for, say, reading text from the disk that has been purged from memory. The application must set the function to TRUE if it made any changes to TBuf.
  1770.  
  1771. hNewBuf. Called to obtain a new text buffer. It is taken in the form of:
  1772.  
  1773.  
  1774. FUNCTION hNewBuf (WS:WSHandle; VAR TBuf:TextBlock):Boolean;
  1775.  
  1776.  
  1777. WS is the WSHandle in which the new text buffer will be assigned to.
  1778.  
  1779. TBuf is a TextBlock record to be initialized. Upon entry, the TBBegin, TBEnd, and TBHandle fields are initialized (TBHandle contains a handle of text).  All other fields are set to zero.
  1780.  
  1781. If the application creates the remaining data structures (TBCTL, TBLines) it must pass TRUE in the function result;  a return of FALSE causes WS to go ahead and create the rest of TBuf.
  1782.  
  1783.  
  1784.  
  1785.  
  1786.  
  1787. hDeleteBuf. Called before deleting a text buffer.  It is taken in the form of:
  1788.  
  1789.  
  1790. FUNCTION hDeleteBuf (WS:WSHandle; VAR TBuf:TextBlock):Boolean;
  1791.  
  1792.  
  1793. WS is the WSHandle containing this text buffer.
  1794.  
  1795. TBuf is the TextBlock to be deleted.  Unlike hFmtDelete for FormatRec elements, hDeleteBuf expects the application to actually dispose TBuf's memory structures.  The application is to only delete the memory structures in TBuf -- not the entry itself in the TextBlock array.
  1796.  
  1797. If the function returns TRUE, WS assumes the memory structures in TBuf were disposed and deletes the entry from the TextBlockArray; otherwise it goes ahead and disposes the memory first before the deletion.
  1798.  
  1799. Note, however, that if you set any of the memory structures in TBuf to NIL (TBLines, TBHandle, or TBCTL) and pass FALSE for the function result, WS won't try to dispose the NIL handles so this is another way to perform "deletion."
  1800.  
  1801.  
  1802.  
  1803.  
  1804. hPreDraw. Called before displaying a line.  It is taken as:
  1805.  
  1806.  
  1807. PROCEDURE hPreDraw (WS:WSHandle; VAR Line:LineRec);
  1808.  
  1809.  
  1810. This particular routine allows the application to examine the contents of a line record just before it is drawn and take appropriate action.  A typical example of hPreDraw would be to set some specific justification for a particular paragraph.
  1811.  
  1812.  
  1813.  
  1814.  
  1815. hPostDraw.  Called after WS is completely done drawing text.  The text drawn could have been a single character (such as a response to WSKey) or multiple lines of text;  in any case, hPostDraw gives the application a chance to add any misc. items to the screen (such as "ruler" settings, page break lines, etc.). It also allows drawing special global elements that could have been erased as a result of the drawing.  It is taken in the form of:
  1816.  
  1817. PROCEDURE hPostDraw (WS:WSHandle);
  1818.  
  1819.  
  1820. The only parameter is WS which is the WSHandle just drawn.
  1821.  
  1822.  
  1823. WARNING: YOU MAY NOT ENTER ANY WS ROUTINES WHILE EXECUTING ANY OF THE ABOVE HOOKS. YOU MAY, HOWEVER, ENTER OTHER LOW-LEVEL HOOKS.
  1824.  
  1825.  
  1826.  
  1827. Tips & Hints on using Low-Level Hooks
  1828.  
  1829.  
  1830. 1. Text editing will slow down dramatically if you have long, data-crunching routines for some of the hooks.  The more important speed-critical hooks are hMeasureText, hDrawText, hTabWidth, and hWordBreak.  Of these four, the two most critical are hMeasureText and hWordBreak since they are called many times during the course of large text calculations.  You should optimize your code as much as possible when patching into any of these.
  1831.  
  1832. 2. You may never re-enter any main WS routine while executing a hook.  The result will be a major crash.  The hooks have been carefully designed to provide most of the information you will need to execute even the most unusual customization.
  1833.  
  1834. 3. It is OK to set the ClipRgn of the current GrafPort while a hook is executing.  WS will restore the original ClipRgn before its final return to the application from the main routine it entered.
  1835.  
  1836. 4. You cannot assume the current GrafPort is the same one you had set when entering a WS procedure or function.  Drawing often occurs to an offscreen bitmap (or PixMap if color).
  1837.  
  1838. 5. If you have both a UserStyle and a WSHooks element for the same procedure (for instance, both UserStyle and WSHooks have an hMeasureText), WS gives priority to the UserStyle and will call it and not  the WSHook whenever that conflict exists.
  1839.  
  1840. 6. For UserStyles, it is NOT a good idea to imbed memory structures (such as picture handles) into text -- WS might delete a piece of it before you get a chance to dispose of the structure;  it can also be erroneously considered a piece of 2-byte script by Script Manager. In any event, it's a bad move and you're asking for trouble.  Instead, insert some unique reference number (preferably in UserSpace field) that can index the data somewhere else in your code.
  1841.  
  1842. 7. UserStyles work just like any other style change -- that means they won't take effect until that style's range  encloses at least one byte.  If necessary, you should insert a dummy character (preferably a non-control character) after a WSSetUserStyle if you want the "style" to take effect immediately.  You can also avoid drawing the dummy character by use of the hDrawText UserStyle hook.
  1843.  
  1844. 8. If you save a WSHandle to disk or some other resource, remember that your UserStyle hooks will no longer by valid when the file is re-opened later on (the ProcPtr values will point to the old  program locations).  To avoid this problem, you "walk through" all the UserStyles (using WSFindUserStyle) and replace the hooks before doing anything else with the WSHandle.  WSFindUserStyle is guaranteed to work even with "bad" UserStyle hooks since nowhere in that routine do any hooks get called.
  1845.  
  1846.